#ifndef STRING_UTIL_H
#define STRING_UTIL_H

#include <string>
#include <memory>
#include <vector>

namespace utils
{
/**
 * @brief:  是否区分大小写
 */
enum CaseSensitivity
{
  CaseInsensitive = 0,//不区分大小写
  CaseSensitive       //区分大小写
};

/**
 * @brief:  分割字符串的行为定义
 */
enum SplitBehavior
{
  KeepEmptyParts = 0, //如果字段是空的，也放在结果里
  SkipEmptyParts      //如果字段是空的，不放在结果里
};
/**
 * 常用字符串工具，基于std::string，用于ASCII字符串处理，对std::string的补充
 *
 * @author: haitao.lin
 */
class StringUtil
{
public:

  StringUtil();

  /**
   * Supports C-style string formatting
   * used with caution in the loop
   */
  template<typename ... Args>
  static std::string format(const char *format, Args ... args)
  {
    auto size_buf = std::snprintf(nullptr, 0, format, args ...) + 1;
    std::unique_ptr<char[]> buf(new(std::nothrow) char[size_buf]);

    if (!buf)
      return std::string("");

    std::snprintf(buf.get(), size_buf, format, args ...);
    return std::string(buf.get(), buf.get() + size_buf - 1);
  }

  /**
   * Returns a lowercase copy of the string.
   */
  static std::string toLower(const std::string &origin_str);

  /**
   * Returns an uppercase copy of the string.
   */
  static std::string toUpper(const std::string &origin_str);

  /**
   * Returns true if the string starts with s; otherwise returns false.
   * If cs is sh::CaseSensitive (default), the search is case sensitive;
   * otherwise the search is case insensitive.
   */
  static bool startsWith(const std::string &origin_str, const std::string &substr,
                         CaseSensitivity cs = CaseSensitivity::CaseSensitive);

  /**
   * Returns true if the string ends with s; otherwise returns false.
   * If cs is sh::CaseSensitive (default), the search is case sensitive;
   * otherwise the search is case insensitive.
   */
  static bool endsWith(const std::string &origin_str, const std::string &substr,
                       CaseSensitivity cs = CaseSensitivity::CaseSensitive);

  /**
   * Compares s1 with s2 and returns an integer less than, equal to,
   * or greater than zero if s1 is less than, equal to, or greater than s2.
   *
   * If cs is sh::CaseSensitive, the comparison is case sensitive; otherwise the comparison is case insensitive.
   */
  static int compare(const std::string &s1, const std::string &s2,
                     CaseSensitivity cs = CaseSensitivity::CaseSensitive);

  /**
   * Returns true if this string contains an occurrence of the string str;
   * otherwise returns false.
   *
   * If cs is sh::CaseSensitive (default), the search is case sensitive;
   * otherwise the search is case insensitive.
   */
  static bool contains(const std::string &str, const std::string &substr,
                       CaseSensitivity cs = CaseSensitivity::CaseSensitive);

  /**
   * Splits the string into substrings wherever sep occurs, and returns the list of those strings.
   * If sep does not match anywhere in the string, split() returns a single-element list containing this string.
   * cs specifies whether sep should be matched case sensitively or case insensitively.
   * If behavior is sh::SkipEmptyParts, empty entries don't appear in the result.
   * By default, empty entries are kept.
   */
  static std::vector<std::string> split(const std::string &str, const std::string &sep,
                                        SplitBehavior behavior = SplitBehavior::KeepEmptyParts,
                                        CaseSensitivity cs = CaseSensitivity::CaseSensitive);

  /**
   * Returns a string that has token removed from the start.
   */
  static std::string trimLeft(const std::string &str, const std::string &token = " ");

  /**
   * Returns a string that has token removed from the end.
   */
  static std::string trimRight(const std::string &str, const std::string &token = " ");

  /**
   * Returns a string that has token removed from the start and end.
   */
  static std::string trim(const std::string &str, const std::string &token = " ");

  /**
   * Returns a string that has whitespace removed from the start and the end.
   * This includes the ASCII characters '\t', '\n', '\v', '\f', '\r', and ' '.
   */
  static std::string trimmed(const std::string &str);

  /**
   * Replaces n characters beginning at index position with the string after and returns a reference to this string.
   */
  static std::string replace(const std::string &str, const std::string &src, const std::string &dest);
};
}

#endif //STRING_UTIL_H
